package search.impl;

import main.SearchManager;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import search.Parser;
import search.WebSpider;
import vo.Program;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Spider extends GetAll implements WebSpider
{

	private final String postgraduateTaughtEntry = "https://www.liverpool.ac.uk/study/postgraduate-taught/courses/";
	private final String postgraduateResearchEntry = "https://www.liverpool.ac" +
			".uk/study/postgraduate-research/opportunities/";
	private final String basisEntry = "https://www.liverpool.ac.uk";
	public Parser getParser()
	{
		return new WebParser();
	}
	//根据A-Z扒Research
	public List<String> getResearchHtmlFromWebAtoZ()
	{
		ArrayList<String> htmls = new ArrayList<String>();
		ArrayList<Thread> threads = new ArrayList<Thread>();
		ArrayList<String> urls = new ArrayList<>();
		try
		{
			Document parse = Jsoup.parse(getAllHtml(postgraduateResearchEntry));
			Elements datatable = parse.getElementsByClass("datatable");
			for (Element element : datatable)
			{

				Elements as = element.getElementsByTag("a");
				for (Element a : as)
				{
					if (!a.attr("href").startsWith("/study"))
					{
						String url = basisEntry + a.attr("href");
						Thread thread = new Thread(new GetAllHtmlRunner(url, htmls));
						thread.start();
						threads.add(thread);
						urls.add(url);
					}
				}
			}
		}
		catch (FileNotFoundException e)
		{
			System.err.println("FileNotFound");
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		wait(threads, urls, htmls);
		return htmls;
	}

	//根据department扒Taught
	public List<String> getTaughtHtmlFromWeb()
	{
		ArrayList<String> urls = new ArrayList<>();
		List<String> taughtHtml = new ArrayList<String>();
		ArrayList<Thread> threads = new ArrayList<Thread>();
		try
		{
			Document parse = Jsoup.parse(getAllHtml(postgraduateTaughtEntry));
			Elements datatable = parse.getElementsByClass("datatable");
			for (Element element : datatable)
			{

				Elements as = element.getElementsByTag("a");
				for (Element a : as)
				{
					if (a.attr("href").startsWith("departments"))
					{
						String url = postgraduateTaughtEntry + a.attr("href");
						Thread thread = new Thread(new GetHtmlAsync(taughtHtml, url));
						thread.start();
						threads.add(thread);
						urls.add(url);
					}
				}
			}

		}
		catch (FileNotFoundException e)
		{
			System.err.println("FileNotFound");
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		wait(threads, urls, (ArrayList<String>) taughtHtml);

		return taughtHtml;
	}

	/**
	 * 根据A-Z扒Taught，结果是不同的
	 * @return
	 */
	public List<String> getTaughtHtmlFromWebByAZ()
	{
		ArrayList<String> htmls = new ArrayList<String>();
		ArrayList<Thread> threads = new ArrayList<Thread>();
		ArrayList<String> urls = new ArrayList<>();
		try
		{
			Document parse = Jsoup.parse(getAllHtml(postgraduateTaughtEntry));

			Elements datatable = parse.getElementsByClass("datatable");
			for (Element element : datatable)
			{

				Elements as = element.getElementsByTag("a");
				for (Element a : as)
				{
					if (a.attr("href").startsWith("/study/"))
					{
						String url = basisEntry + a.attr("href");
						Thread thread = new Thread(new GetAllHtmlRunner(url, htmls));
						thread.start();
						urls.add(url);
						threads.add(thread);
					}
				}
			}
		}
		catch (FileNotFoundException e)
		{
			System.err.println("FileNotFound");
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		wait(threads, urls, htmls);


		return htmls;
	}

	//保持线程同步
	private void wait(ArrayList<Thread> threads, ArrayList<String> urls, ArrayList<String> htmls)
	{
		boolean isAllFinish;
		long startMill = System.currentTimeMillis();
		boom:do
		{
			isAllFinish = true;
			int aliveCount = 0;
			for (Thread thread : threads)
			{
				if (thread.isAlive())
				{
					aliveCount++;
					isAllFinish = false;
					long nowMill = System.currentTimeMillis();
					if(nowMill - startMill >= 30000)
					{
						break boom;
					}
				}
			}
			System.out.println(aliveCount);
//			Scanner scanner = new Scanner(System.in);
//			int i = scanner.nextInt();
//			System.err.println(i);
		}while (!isAllFinish);
		if(!isAllFinish)
		{
			for (Thread thread : threads) {
				if(thread.isAlive())
				{

					try {
						System.err.println("start single");
						htmls.add(getAllHtml(urls.get(threads.indexOf(thread))));
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}

	/**
	 * 获得所有的Html
	 *
	 * @return 每一个String是一个页面的所有Html
	 */
	public List<String> getTaughtHtml()
	{
		return getTaughtHtmlFromWebByAZ();
	}

	public List<String> getResearchHtml()
	{
		return getResearchHtmlFromWebAtoZ();
	}

	public List<String> getHtmlFromWeb()
	{
		List<String> returner = new ArrayList<String>();
//		List<String> taughtHtml = getTaughtHtmlFromWebByAZ();
		List<String> researchHtml = getResearchHtmlFromWebAtoZ();
//		returner.addAll(taughtHtml);
		returner.addAll(researchHtml);
		return returner;
	}
	public static ArrayList<Program> spider(int type) throws IndexOutOfBoundsException
	{
		//Type 1: taught
		//Type 2: Research
		//Type 3: taught && Research
		try {
			Class.forName("search.impl.Manager");
		} catch (ClassNotFoundException e) {
			System.out.println("Manager类不存在");
		}

		List<WebSpider> webSpiders = SearchManager.getWebSpider();

		ArrayList<Program> programs = new ArrayList<Program>();
		for (WebSpider webSpider : webSpiders) {
			Parser parser = webSpider.getParser();
			List<String> pages = new ArrayList<>();
			switch (type) {
				case 1:
					pages = ((Spider)webSpider).getTaughtHtml();
					break;
				case 2:
					pages = ((Spider)webSpider).getResearchHtml();
					break;
				case 3:
					pages = webSpider.getHtmlFromWeb();
					break;
				default:
					throw new IndexOutOfBoundsException("Only Type 1, Type2, Type3!");
			}
			for (String page : pages) {
				programs.add(parser.parseHtml(page));
			}
		}
		return programs;
	}


	public static ArrayList<Program> spider()
	{
		return spider(3);
	}
}

